/**
 * Created by PengWei on 2018/7/24.
 */


namespace mengdao {
    /**
     *  配置管理
     *  只当Context初始化完成之后，调用配置的configure方法
     */
    export class ConfigManager {
        private _objectProcessor: ObjectProcessor = new ObjectProcessor();
        private _configs: Map<any, boolean> = new Map<any, boolean>();
        private _queue: any[] = [];
        private _initialized: boolean = false;
        private _context: Context;
        private readonly _injector: Injector;

        public constructor(context: Context) {
            this._context = context;
            this._injector = context.injector;
            this.addConfigHandler(new ClassMatcher(), this.handleClass.bind(this));
            this.addConfigHandler(new ObjectWatcher(), this.handleObject.bind(this));

            context.once(ContextEvent.INITIALIZE, this.onInitialize, this, false, -100);
        }

        public addConfig(config: any): void {
            if (!this._configs.has(config)) {
                this._configs.set(config, true);
                this._objectProcessor.processObject(config);
            }
        }

        private onInitialize(e: ContextEvent): void {
            if (!this._initialized) {
                this._initialized = true;
                this.processQueue();
            }
        }

        private handleObject(object: any): void {
            if (this._initialized) {
                this.processObject(object);
            } else {
                this._queue.push(object);
            }
        }

        private processQueue(): void {
            for (let i in this._queue) {
                if (this._queue.hasOwnProperty(i)) {
                    let config: any = this._queue[i];
                    if (typeof config === "function") {
                        this.processClass(config);
                    } else {
                        this.processObject(config);
                    }
                }
            }
            this._queue.length = 0;
        }

        public addConfigHandler(matcher: IMatcher, handler: Function): void {
            this._objectProcessor.addObjectHandler(matcher, handler);
        }

        private handleClass(type: IClass<IConfig>): void {
            if (this._initialized) {
                this.processClass(type);
            } else {
                this._queue.push(type);
            }
        }

        private processClass(type: IClass<IConfig>): void {
            let config: IConfig = mengdao.instantiateUnmapped(this._injector, type);
            if (config) {
                config.configure();
            }
        }

        private processObject(object: any): void {
            let config: IConfig = <IConfig>object;
            if (config && config.configure) {
                config.configure();
            }
        }

        public destroy(): void {
            this._objectProcessor.removeAllHandlers();
            this._queue.length = 0;
            this._configs.clear();
        }
    }
}